'use strict';

const autoprefixer = require('autoprefixer');
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const ManifestPlugin = require('webpack-manifest-plugin');
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin');
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const paths = require('./paths');
const getClientEnvironment = require('./env');

const publicPath = paths.servedPath;
const shouldUseRelativeAssetPaths = publicPath === './';
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';

const publicUrl = publicPath.slice(0, -1);
const env = getClientEnvironment(publicUrl);

if (env.stringified['process.env'].NODE_ENV !== '"production"') {
	throw new Error('Production builds must have NODE_ENV=production.');
}

const cssFilename = 'static/css/[name].[contenthash:8].css';


const extractTextPluginOptions = shouldUseRelativeAssetPaths
		? // Making sure that the publicPath goes back to to build folder.
		{ publicPath: Array(cssFilename.split('/').length).join('../') }
		: {};

module.exports = {
	bail: true,
	devtool: shouldUseSourceMap ? 'source-map' : false,
	entry: [
		paths.appIndexJs
	],
	output: {
		path: paths.appBuild,
		filename: 'static/js/[name].[chunkhash:8].js',
		chunkFilename: 'static/js/[name].[chunkhash:8].chunk.js',
		publicPath: publicPath,
		devtoolModuleFilenameTemplate: info =>
				path
						.relative(paths.appSrc, info.absoluteResourcePath)
						.replace(/\\/g, '/'),
	},
	resolve: {
		modules: ['node_modules', paths.appNodeModules].concat(
				process.env.NODE_PATH.split(path.delimiter).filter(Boolean)
		),
		extensions: ['.web.js', '.mjs', '.js', '.json', '.web.jsx', '.jsx'],
		alias: {
			'react-native': 'react-native-web',
			'@': paths.appSrc
		},
		plugins: [
			new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson]),
		],
	},
	module: {
		strictExportPresence: true,
		rules: [
			{
				test: /\.(js|jsx|mjs)$/,
				enforce: 'pre',
				loader: require.resolve('babel-loader'),
				include: paths.appSrc,
			},
			{
				oneOf: [
					{
						test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
						loader: require.resolve('url-loader'),
						options: {
							limit: 10000,
							name: 'static/media/[name].[hash:8].[ext]',
						},
					},
					{
						test: /\.(js|jsx|mjs)$/,
						include: paths.appSrc,
						loader: require.resolve('babel-loader'),
					},
					{
						test: /\.(css|scss|styl)$/,
						loader: ExtractTextPlugin.extract(
								Object.assign(
										{
											fallback: {
												loader: require.resolve('style-loader'),
												options: {
													hmr: false,
												},
											},
											use: [
												{
													loader: require.resolve('css-loader'),
													options: {
														importLoaders: 1,
														minimize: true,
														sourceMap: shouldUseSourceMap,
													},
												},
												{
													loader: require.resolve('postcss-loader'),
													options: {
														ident: 'postcss',
														plugins: () => [
															require('postcss-flexbugs-fixes'),
															autoprefixer({
																browsers: [
																	'>1%',
																	'last 4 versions',
																	'Firefox ESR',
																	'not ie < 9', // React doesn't support IE8 anyway
																],
																flexbox: 'no-2009',
															}),
														],
													},
												},
												{
													loader: require.resolve('sass-loader') // compiles Less to CSS
												},
												{
													loader: require.resolve('stylus-loader') // compiles stylus to CSS
												}
											],
										},
										extractTextPluginOptions
								)
						),
					},
					{
						loader: require.resolve('file-loader'),
						exclude: [/\.(js|jsx|mjs)$/, /\.html$/, /\.json$/],
						options: {
							name: 'static/media/[name].[hash:8].[ext]',
						},
					},
				],
			},
		],
	},
	plugins: [
		new InterpolateHtmlPlugin(env.raw),
		new HtmlWebpackPlugin({
			inject: true,
			template: paths.appHtml,
			minify: {
				removeComments: true,
				collapseWhitespace: true,
				removeRedundantAttributes: true,
				useShortDoctype: true,
				removeEmptyAttributes: true,
				removeStyleLinkTypeAttributes: true,
				keepClosingSlash: true,
				minifyJS: true,
				minifyCSS: true,
				minifyURLs: true,
			},
		}),
		new webpack.DefinePlugin(env.stringified),
		new webpack.optimize.UglifyJsPlugin({
			compress: {
				warnings: false,
				comparisons: false,
			},
			mangle: {
				safari10: true,
			},
			output: {
				comments: false,
				ascii_only: true,
			},
			sourceMap: shouldUseSourceMap,
		}),
		new ExtractTextPlugin({
			filename: cssFilename,
		}),
		new ManifestPlugin({
			fileName: 'asset-manifest.json',
		}),
		new SWPrecacheWebpackPlugin({
			dontCacheBustUrlsMatching: /\.\w{8}\./,
			filename: 'service-worker.js',
			logger(message) {
				if (message.indexOf('Total precache size is') === 0) {
					return;
				}
				if (message.indexOf('Skipping static resource') === 0) {
					return;
				}
				console.log(message);
			},
			minify: true,
			navigateFallback: publicUrl + '/index.html',
			navigateFallbackWhitelist: [/^(?!\/__).*/],
			staticFileGlobsIgnorePatterns: [/\.map$/, /asset-manifest\.json$/],
		}),
		new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
		new MiniCssExtractPlugin({})
	],
	node: {
		dgram: 'empty',
		fs: 'empty',
		net: 'empty',
		tls: 'empty',
		child_process: 'empty',
	},
};
